<?php
namespace Zaya\Lib\SSO;

use Zaya\Lib\Exceptions\SimpleErrorException;

class Server extends Base
{
    /**
     * @var int 登录状态过期时间(分钟)
     */
    public static $loginAliveMinute = 30;
    /**
     * @return string
     * @throws SimpleErrorException
     */
    public function getServerToken() {
        static $token = null;
        if ($token) {
        } elseif ($token = $_COOKIE['sso_token'] ?? null) {
        } elseif ($token = $this->getServerTokenByClientToken(\request('client_id'), \request('client_token'))) {
        } else {
            $token = base_convert(md5(uniqid(rand(), true)), 16, 36);
            // 30天
            setcookie('sso_token', $token, time() + 2592000, '/');
        }
        return $token;
    }

    /**
     * @throws SimpleErrorException
     */
    public function attach() {
        $clientId = request('client_id');
        $clientToken = request('client_token');
        if (!$clientId) {
            throw new SimpleErrorException('缺少参数: client_id', 400);
        }
        if (!$clientToken) {
            throw new SimpleErrorException('缺少参数: client_token', 400);
        }

        if (!request('return_url')) {
            throw new SimpleErrorException("缺少参数: return_url", 400);
        }

        $checksum = $this->generateChecksum('attach', $clientId, $clientToken);

        if (request('checksum') != $checksum) {
            throw new SimpleErrorException("参数错误: checksum", 400);
        }

        // 将 SSO Client Token 与 SSO Server Session Id 绑定
        $this->clientTokenBindServerToken($clientId, $clientToken);

        return $this->output(['attach success']);
    }

    /**
     * 将 SSO Client Token 与 SSO Server Session Id 绑定
     * @param $clientId
     * @param $token
     * @throws SimpleErrorException
     */
    public function clientTokenBindServerToken($clientId, $token) {
        try {
            $serverToken = $this->getServerToken();
            \Cache::set("SSOClientTokenBindServerToken:{$clientId}-{$token}" , $serverToken, static::$loginAliveMinute);
            $key = "SSOServerTokenHaveClientToken:" . $serverToken;
            $clientTokenArr = \Cache::get($key);
            $clientTokenArr[$clientId] = $token;
            // 30天
            \Cache::set($key, $clientTokenArr, 43200);
        } catch (\Exception $e) {
            throw new SimpleErrorException($e->getMessage(), $e->getCode());
        } catch (\Psr\SimpleCache\InvalidArgumentException $e) {
            throw new SimpleErrorException($e->getMessage(), $e->getCode());
        }
    }

    /**
     * 通过 Client Token 获取 Server Token
     * @param $clientId
     * @param $token
     * @return string
     * @throws SimpleErrorException
     */
    public function getServerTokenByClientToken($clientId, $token) {
        try {
            return \Cache::get("SSOClientTokenBindServerToken:{$clientId}-{$token}");
        } catch (\Exception $e) {
            throw new SimpleErrorException($e->getMessage(), $e->getCode());
        }
    }

    public function output($params) {
        if (request('callback')) {
            return response()->jsonp(request('callback'), $params);
        }
        if (request('return_url')) {
            return redirect(request('return_url'));
        }
        return $params;
    }


    /**
     * Generate session id from session token
     * @param string $command
     * @param string $clientId
     * @param string $clientToken
     * @return string
     */
    protected function generateChecksum($command, $clientId, $clientToken)
    {
        $clientSecert = $this->getClientSecret($clientId);

        if (is_null($clientSecert)) return null;

        return $this->generateChecksumSub($command, $clientToken, $clientSecert);
    }

    /**
     * Get the API secret of a broker and other info
     *
     * @param string $clientId
     * @return array
     */
    protected function getClientSecret($clientId)
    {
        static $clients;
        if (is_null($clients)) {
            $clients = config('sso.server');
        }
        return $clients[$clientId] ?? null;
    }
}
